package vis.core.common.util;

import org.springframework.util.AntPathMatcher;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class StringKit {
    /**
     * 字符串替换填充
     *
     * @param string 字符串，识别 {} 进行填充
     * @param objs   填充内容数组
     * @return 返回替换并填充后的新字符串
     */
    public static String format(String string, Object... objs) {
        return format(0, string, objs);
    }

    public static void formatPrint(String string, Object... objs) {
        System.out.println(format(0, string, objs));
    }

    public static String subBefore(String finStr, String content) {
        if (isBlank(content) || isBlank(finStr) || !content.contains(finStr)) {
            return null;
        }
        int index = content.indexOf(finStr);
        //        System.out.println(content);
        //        System.out.println(index);
        //        System.out.println(content.substring(0, index));
        return content.substring(0, index);
    }

    public static String subAfter(String finStr, String content) {
        if (isBlank(content) || isBlank(finStr) || !content.contains(finStr)) {
            return null;
        }
        int index = content.indexOf(finStr);
        //        System.out.println(content);
        //        System.out.println(index);
        //        System.out.println(content.substring(index + finStr.length()));
        return content.substring(index + finStr.length());
    }

    //copy to org.apache.commons
    public static boolean isBlank(CharSequence cs) {
        if (cs == null) return true;

        int strLen = length(cs);
        if (strLen != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

        }
        return true;
    }

    //copy to org.apache.commons
    public static String isBlank(String cs, String defaultValue) {
        if (isBlank(cs)) return defaultValue;
        return cs;
    }

    //copy to org.apache.commons
    public static int length(CharSequence cs) {
        return cs == null ? 0 : cs.length();
    }

    //copy to org.apache.commons
    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

//    public static void main(String[] args) {
//        String join1 = StringKit.join(ArrayKit.asList("1", "10", "20", ""), ",");
//        String join2 = StringKit.join(ArrayKit.asList("", "1", "10", "20", ""), ",");
//        System.out.println(join1);
//        System.out.println(join2);
//    }

    //copy to org.apache.commons
    public static String join(Iterable<?> iterable) {
        return iterable == null ? null : join(iterable.iterator(), ",");
    }

    //copy to org.apache.commons
    public static String join(Iterable<?> iterable, String separator) {
        return iterable == null ? null : join(iterable.iterator(), separator);
    }

    //copy to org.apache.commons
    public static String join(Iterator<?> iterator, String separator) {
        if (iterator == null) {
            return null;
        } else if (!iterator.hasNext()) {
            return "";
        } else {
            Object first = iterator.next();
            if (!iterator.hasNext()) {
                return Objects.toString(first, "");
            } else {
                StringBuilder buf = new StringBuilder(256);
                if (first != null) {
                    buf.append(first);
                }

                while (iterator.hasNext()) {
                    if (separator != null) {
                        buf.append(separator);
                    }

                    Object obj = iterator.next();
                    if (obj != null) {
                        buf.append(obj);
                    }
                }

                return buf.toString();
            }
        }
    }

    public static boolean isNull(Object object) {
        return object == null;
    }

    /**
     * 字符串替换填充
     *
     * @param capacity 初始扩容大小（可选配置）
     * @param string   字符串，识别 {} 进行填充
     * @param objs     填充内容数组
     * @return 返回替换并填充后的新字符串
     */
    private static String format(int capacity, String string, Object... objs) {
        String replace = string.replace("{}", "#X#9527#X#");
        String[] split = replace.split("#X#9527#X#");

        StringBuilder stringBuilder = new StringBuilder();

        if (capacity == 0) {
            new StringBuilder((int) (replace.length() * 1.5));
        } else {
            new StringBuilder(capacity);
        }

        for (int i = 0; i < split.length; i++) {
            stringBuilder.append(split[i]);
            if (objs != null && objs.length > i) {
                if (objs[i] != null) {
                    stringBuilder.append(objs[i]);
                } else {
                    stringBuilder.append("NULL");
                }
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 分隔字符串，返回数组
     * 默认逗号分隔
     * 默认排除空字符串，并且去重
     */
    public static ArrayList<String> split(String content) {
        return split(content, ",", true, true);
    }

    /**
     * 分隔字符串，返回数组
     * 默认排除空字符串，并且去重
     */
    public static ArrayList<String> split(String content, String splitStr) {
        return split(content, splitStr, true, true);
    }

    /**
     * 分隔字符串，返回数组
     * 排除空字符串
     */
    public static ArrayList<String> split(String content, String splitStr, boolean excludeBlank) {
        return split(content, splitStr, excludeBlank, false);
    }

    /**
     * 分隔字符串，返回数组
     * 条件判断：是否排除空字符串  是否去重
     */
    public static ArrayList<String> split(String content, String splitStr, boolean excludeBlank,
                                          boolean excludeRepeat) {
        if (isBlank(content)) return new ArrayList<>();
        if (isBlank(splitStr)) {
            ArrayList<String> list = new ArrayList<>();
            list.add(content);
            return list;
        }
        String[] split = content.split(splitStr);
        ArrayList<String> list = new ArrayList<>();

        //先排除符号
        if (excludeBlank) {
            for (String value : split) {
                if (!splitStr.equals(value)) {
                    list.add(value);
                }
            }
        }

        ArrayList<String> returnList = new ArrayList<>(list.size());
        //排除空值
        if (excludeBlank) {
            for (String value : split) {
                if (isNotBlank(value)) {
                    returnList.add(value);
                }
            }
        }
        //去重
        if (excludeRepeat) {
            returnList = new ArrayList<>(new HashSet<>(returnList));
        }

        return returnList;
    }


    // 例：/sys/manage/add?token=xxx&salt=yyy
    public static Map<String, String> getUriParam(String uri) {
        return getURI_URL_Param("1", uri);
    }

    // 例：http://192.168.110.116:8090/sys/manage/add?token=xxx&salt=yyy
    public static Map<String, String> getUrlParam(String url) {
        return getURI_URL_Param("2", url);
    }

    // 例：?token=xxx&salt=yyy 或者 token=xxx&salt=yyy
    public static Map<String, String> getUrlEndParam(String uri) {
        return getURI_URL_Param("3", uri);
    }

    private static Map<String, String> getURI_URL_Param(String type, String uri) {
        if (isBlank(uri)) return null;
        String query = "";

        if ("1".equals(type)) {
            URI obj;
            try {
                obj = new URI(uri);
                query = obj.getQuery();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        if ("2".equals(type)) {
            URL obj;
            try {
                obj = new URL(uri);
                query = obj.getQuery();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        if ("3".equals(type)) {
            query = uri;
            if (uri.startsWith("?")) {
                query = uri.substring(1);
            }
        }

        Map<String, String> params = new HashMap<>();
        String[] pairs = query.split("&");
        for (String pair : pairs) {
            int idx = pair.indexOf("=");
            String key;
            String value;
            try {
                key = URLDecoder.decode(pair.substring(0, idx), "UTF-8");
                value = URLDecoder.decode(pair.substring(idx + 1), "UTF-8");
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            params.put(key, value);
        }
        return params;
    }

    //生成随机位数字符串
    public static String createRandom(int length) {
        return createRandom(length, false);
    }

    //生成随机位数字符串
    public static String createRandom(int length, boolean dontZeroStart) {
        return createRandom(length, dontZeroStart, new ArrayList<>());
    }

    //生成随机位数字符串
    public static String createRandom(int length, boolean dontZeroStart, List<String> notInList) {
        StringBuilder randomStr = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            int randomNumber = random.nextInt(10);
            if (i == 0 && dontZeroStart && randomNumber == 0) {
                i--;
            } else {
                randomStr.append(randomNumber);
            }
        }
        if (notInList.contains(randomStr.toString())) {
            return createRandom(length, dontZeroStart, notInList);
        } else {
            return randomStr.toString();
        }
    }

    public static CharSequence md5(String number) {
        MessageDigest messageDigest;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
            return null;
        }
        byte[] resultByte = messageDigest.digest(number.getBytes());
        StringBuilder result = new StringBuilder();
        for (byte b : resultByte) {
            int v = 0xFF & b;
            if (v < 16) {
                result.append("0");
            }
            result.append(Integer.toHexString(v));
        }
        return result.toString();
    }

    public static String blankDefStr(String value, String defaultStr) {
        if (isBlank(value)) return defaultStr;
        return value;
    }

    public static boolean has(String str, String... any) {
        List<String> list = ArrayKit.asList(any);
        return list.contains(str);
    }

    public static String getExceptionMsg(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }

    //URI通配符规则匹配对象
    public static final AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * 根据传入的数据，过滤后返回最终保留的数据
     *
     * @param allHasRes     全部具备的资源
     * @param allExcludeRes 需要排除的资源
     * @return 剩余保留的资源
     */
    public static HashSet<String> pathMatcherHasData(HashSet<String> allHasRes, Collection<String> allExcludeRes) {
        //如果什么都没有，返回空数组
        if (allHasRes == null || allHasRes.size() == 0) return new HashSet<>();
        //如果什么都没排除，则所有资源都具备
        if (allExcludeRes == null || allExcludeRes.size() == 0) return allHasRes;

        //遍历排除资源，在遍历具备资源，最终得出，具备资源
        HashSet<String> endMenuHasRes = new HashSet<>();
        for (String excludeRes : allExcludeRes) {
            for (String hasRes : allHasRes) {
                boolean matchExclude = pathMatcher.match(excludeRes, hasRes);
                // 如果具备资源与排除资源不匹配 matchExclude=false，说明可以保留
                if (!matchExclude) endMenuHasRes.add(hasRes);
            }
        }
        return endMenuHasRes;
    }

//    public static void main(String[] args) {
//        Map<String, String> urlEndParam = getUrlEndParam("token=xxx&salt=yyy");
//        System.out.println(JSONObject.toJSONString(urlEndParam));
//    }
}
